home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / qlib.arc / QLIB.DOC < prev    next >
Encoding:
Text File  |  1989-01-24  |  44.9 KB  |  1,100 lines

  1.  
  2.     QLIB library version 1.2 for the QuickBASIC compiler
  3.     (c) 1988 Douglas Herr
  4.  
  5. WHY USE QLIB?
  6.  
  7.     QuickBASIC represents an enormous leap in BASIC programming over
  8.     interpreted BASICA or GWBASIC, and is a language that many programmers
  9.     already know.  However, many programmers also know that many QuickBASIC
  10.     commands are not all that quick, can be extremely cumbersome, and/or
  11.     will hog tremendous amounts of memory.  QLIB is a library of Assembly-
  12.     language subroutines which provides quick, compact solutions to many of
  13.     QuickBASIC's problems.
  14.  
  15.     Many of QLIB's routines grew out of my own frustration with QuickBASIC's
  16.     deficiencies, particularly QuickBASIC's meager support of the Hercules
  17.     video graphics card.  Each QLIB routine has been tested extensively, but
  18.     since I cannot foresee every possible use or abuse of QLIB, I cannot be
  19.     held responsible for any damages resulting from its use.
  20.  
  21.     Ideas for these routines come from a wide variety of sources.  If you want
  22.     to see additional routines, let me hear about it.
  23.  
  24.  
  25. DISTRIBUTION and REGISTRATION
  26.  
  27.     QLIB is NOT public-domain software.  This library is distributed using
  28.     the shareware concept.  Shareware is high-quality software written by
  29.     people like me who would rather spend their time programming than setting
  30.     up marketing channels.  Shareware is the ultimate in try-before-you-buy.
  31.     If you don't like QLIB after trying it, don't register.  If you do like
  32.     it, tell me by registering!  The shareware concept doesn't work if users
  33.     don't support programmers' efforts.
  34.  
  35.     QLIB is an evolving library, so it is likely that by the time you read
  36.     this there will be several additional routines available.  Areas I'm
  37.     particularly working on include 8087 support and Hercules graphics for
  38.     ALL versions of QuickBASIC.  Registered users receive the latest version
  39.     of QLIB available when they register, and may upgrade at any time for
  40.     the paltry fee of $10.00.
  41.  
  42.     QLIB may be freely distributed in un-altered form EXCEPT FOR THE SOURCE
  43.     CODE, and remains my property.  You may use QLIB on a trial basis, but
  44.     you are expected to register if you intend to use it regularly or include
  45.     QLIB routines in your applications.  No royalties are required and
  46.     registration costs only $25, so it makes little sense to not register.
  47.  
  48.     Register by sending $25 to:
  49.  
  50.               Douglas R. Herr
  51.               2026 Marina Court
  52.               San Leandro, CA  94577
  53.               (415) 351-4779
  54.     Any questions or problems should be sent to me at the same address.
  55.     Please include a stamped, self-addressed envelope if you are not a
  56.     registered user.  If you call, more than likely you will talk to
  57.     Iza the Answering Machine.
  58.  
  59.  
  60. HOW DO I USE QLIB?
  61.  
  62.     QLIB was developed for QuickBASIC 4, but many QLIB routines may be used
  63.     with earlier versions of QuickBASIC.  I have tested many routines with
  64.     QuickBASIC 3, and these routines should work equally well with QB2.  As
  65.     of this release, I have not tested QLIB with QB3's QB87.  QB2 and QB3
  66.     users should read Appendix C - QLIB and QB3.
  67.  
  68.     QLIB may be used with QuickBASIC 4 by copying QLIB.QLB and
  69.     QLIB.LIB to your QuickBASIC directory.  (QB3 users should
  70.     use QLIB.EXE in place of QLIB.QLB.)
  71.  
  72.     To load QLIB with the QuickBASIC editor, use the command
  73.  
  74.          QB /L QLIB.QLB
  75.  
  76.     Link QLIB with your object files with
  77.  
  78.          LINK /EX /NOE yourprog,,NUL,QLIB.LIB;
  79.  
  80.          for QB3:
  81.          LINK yourprog,,NUL,QLIB.LIB;
  82.  
  83.     As time permits, QLIB subroutines will be tested and modified, if needed,
  84.     to work with QB3 and QB87.  I have clearly noted in this documentation
  85.     any problems I have found.
  86.  
  87.     QLIB VIDEO routines give your applications more control over the
  88.     display screen than QuickBASIC allows.  You can save and restore
  89.     screen displays, print to the screen at blinding speed, and use screen
  90.     color attributes not possible with QuickBASIC alone.
  91.  
  92.     Two kinds of QLIB video routines are available: Direct Video Memory
  93.     Transfer (DVMT), the fastest available, and BIOS, compatible with a wider
  94.     range of hardware and software.
  95.  
  96.     BIOS video routines use the PC's BIOS and are slower than DVMT routines,
  97.     but are often faster or more flexible than comparable QuickBASIC commands.
  98.  
  99.     DVMT video subroutines take advantage of PC video systems' known video 
  100.     memory addresses and transfer data directly to video memory instead of
  101.     working through DOS or the PC BIOS.  This results in nearly instant video
  102.     displays.  DVMT also provides additional support for the Hercules
  103.     Graphics Card not available through the PC BIOS.  Caution: DVMT subroutines
  104.     may not work properly on PCs which are not close copies of the IBM PC.
  105.     Most PC clones are close copies of the IBM computers.  In fact, QLIB's
  106.     DVMT video routines were developed using a cheap XT clone and a
  107.     Hercules-clone monochrome graphics card.
  108.  
  109.     Video hardware configurations supported include Monochrome Display Adapter
  110.     (MDA), Color Display Adapter (CGA), Hercules Graphics Card (HGC), EGA,
  111.     MCGA and VGA.  I have used these routines with MDA, HGC and EGA systems.
  112.  
  113.     SCREEN PAGES in text mode may be used with all supported video systems
  114.     except the IBM (or compatible) Monochrome Display Adapter.  With CGA
  115.     displays, 4 screen pages are available, and with Hercules (or compatible)
  116.     up to 16 pages may be used with DVMT routines.  For EGA, VGA and 
  117.     MCGA systems, QLIB supports up to 8 pages.  Screen pages may be used to
  118.     store help screens or to save one (or more) screens while another is
  119.     displayed.
  120.  
  121.     CGA screen pages are numbered 0 through 3, and EGA/VGA/MCGA pages
  122.     are numbered 0 through 7.  Hercules screen page numbers may be between
  123.     0 and 15.  Even-numbered pages (0 - 14) may be used at any time, but
  124.     odd-numbered pages (1 - 15) may be used only when the second 32k of
  125.     Hercules memory is included in the memory map (see HPage).
  126.     NOTE: BIOS routines support only page 0 on Hercules systems.
  127.     Subroutine: CalcATTR(foreground%, background%, bright%, blink%, ATTR%)
  128.  
  129.           Calculates the color attribute (ATTR%) for many QLIB video
  130.     routines.  CalcATTR allows use of the "blink" attribute, which may also
  131.     be used for high-intensity backgrounds.  (See SetBLINK.)
  132.  
  133.     Bright% affects only the foreground color, while blink% either makes the
  134.     character blink or causes non-black backgrounds to be bright, depending
  135.     on the last call to SetBLINK.  CalcATTR may be used with either BIOS or
  136.     DVMT video routines.  See Appendix A, "Color Attributes".
  137.  
  138.     Example:
  139.          CALL CALCATTR(foreground%, background%, bright%, blink%, ATTR%)
  140.  
  141.  
  142.  
  143.     Subroutine: SetBLINK(a%)
  144.  
  145.          Enables / disables blinking attributes in text mode.  When blinking
  146.     is disabled, blinking reverse video attributes are changed from normal
  147.     intensity backgrounds to high intensity.  SetBLINK affects all screen
  148.     pages.  SetBLINK uses BIOS calls for EGA, MCGA and VGA systems, and uses
  149.     DVMT for Monochrome, Hercules and CGA.
  150.  
  151.     Example:
  152.          a% = 0
  153.          CALL SetBLINK(a%)  ' turn blink off, high intensity backgrounds on
  154.          a% = 1
  155.          CALL SetBLINK(a%)  ' restore blinking attributes
  156.  
  157.  
  158.  
  159.     Subroutine: Bprint(st$, row%, col%, attr%)
  160.     Subroutine: BprintL(st$, row%, col%, attr%)
  161.     Subroutine: BprintU(st$, row%, col%, attr%)
  162.  
  163.          Uses BIOS calls to print a string on the active video page, allowing
  164.     ALL ASCII characters (unlike QuickBASIC's PRINT command).  You must
  165.     specify row and column starting position, and color attribute.  Does not
  166.     affect cursor position.  Bprint is slower than Qprint, below. Bprint
  167.     should be more usable than Qprint in multi-task enviornments and will be
  168.     compatible with some hardware which is not an exact clone of IBM's PC, XT
  169.     or AT.  Color attribute may be calculated with CalcATTR.
  170.  
  171.     Bprint may also be used in Graphics modes, but the color attribute may
  172.     not work as expected.
  173.  
  174.     BprintL prints A - Z in lower case a - z without changing st$, and
  175.     BprintU prints a - z in upper case A - Z without changing st$.
  176.  
  177.     Example:
  178.          st$="This is a test of screen printing with BIOS calls"
  179.          row%=10: col%=20
  180.          CALL Bprint(st$, row%, col%, attr%)     Subroutine: ClrBlockB(row0%, col0%, row1%, col1%, attr%)
  181.  
  182.          Uses BIOS calls to clear a window of the screen from row0%,
  183.     col0%, to row1%, col1%, where row1% > row0%, col1% > col0%, where row%
  184.     is between 1 and 25 and col% is between 1 and 80.  The window may be
  185.     cleared to any color attribute.  Color attributes may be calculated using
  186.     CalcATTR.  See also Scroll.
  187.  
  188.     Example:
  189.          CALL ClrBlockB(row0%, col0%, row1%, col1%, attr%)
  190.  
  191.  
  192.  
  193.     Subroutine: MaxTextPage(page%)
  194.  
  195.          Uses BIOS calls to determine maximum screen page available to
  196.     BIOS video subroutines (Text mode).  Minimum page number is always 0.
  197.  
  198.     Example:
  199.          CALL MaxTextPage(page%)
  200.          REM  if page% = 0, then MDA or HGC installed
  201.          REM  if page% = 3, then CGA installed
  202.          REM  if page% = 7, then EGA, MCGA or VGA installed
  203.  
  204.  
  205.  
  206.     Subroutine: Scroll(row0%, col0%, row1%, col1%, attr%, lines%)
  207.  
  208.          Uses BIOS calls to scroll a window of the screen lines% rows, 
  209.     limited by row0%, col0%, row1%, col1%.  Positive values of lines% will
  210.     scroll the screen up, negative values scroll the screen down, and lines%
  211.     = 0 will blank the window.  Rows cleared by the scrolling action will be
  212.     set to color attribute attr%.  Scroll may also be used in graphics modes,
  213.     but the color attribute may not work as expected.  Color attributes for
  214.     graphics mode use of Scroll should be background colors only.
  215.  
  216.     Example:
  217.          row0% = 5: col0% = 10: row1% = 15: col1% = 75: lines% = 1
  218.          CALL Scroll(row0%, col0%, row1%, col1%, attr%, lines%)
  219.          REM we just scrolled a window up one row
  220.  
  221.  
  222.  
  223.     Subroutine: TextPage(page%)
  224.  
  225.          Uses BIOS calls to set text mode screen page.  Does NOT affect
  226.     QuickBASIC's PRINT command, or DVMT routines.  LOCATE may be used, and
  227.     LOCATE commands will be saved when changing screen pages via TextPage.
  228.     Use MaxTextPage to determine maximum page number available.
  229.     NOTE: Hercules screen pages other than 0 are not supported by BIOS-call
  230.     subroutines.
  231.  
  232.     Example:
  233.          CALL TextPage(page%) DVMT video routines, below, are much faster than comparable BIOS video routines
  234. or QuickBASIC.  In most cases, DVMT routines require hardware which is 100%
  235. compatible with the IBM PC (as are most clones).
  236.  
  237.     Subroutine: ClrBlock(row0%, col0%, row1%, col1%, attr%)
  238.  
  239.          Uses DVMT to clear a window of the screen from row0%, col0%, to
  240.     row1%, col1%, where row1% > row0%, col1% > col0%, where row% is between
  241.     1 and 25 and col% is between 1 and 80.  The window may be cleared to any
  242.     color attribute. Color attributes may be calculated using CalcATTR.
  243.     ClrBlock works with SetQPage.  See also QScroll.
  244.     
  245.     Example:
  246.          CALL ClrBlock(row0%, col0%, row1%, col1%, attr%)
  247.  
  248.  
  249.  
  250.     Subroutine: ClrScreen(attr%)
  251.  
  252.          Clears the video page set by SetQPage to a specified color attribute.
  253.     Page cleared is determined by the last SetQPage call, and color attributes
  254.     may be calculated using CalcATTR.
  255.  
  256.     Example:
  257.          CALL ClrScreen(attr%)
  258.  
  259.  
  260.     Subroutine: CopyScreen(frompage%, topage%, oops%)
  261.  
  262.          Copies one page of video memory to another.  This may be used
  263.     to save screens to recall later.  Oops% will be set to -1 if the
  264.     display adapter is an MDA or if frompage% = topage%.  For MDA systems,
  265.     use SaveScreen.
  266.  
  267.     All screen pages saved by CopyScreen are erased when the system is 
  268.     set to Graphics mode.  Use SaveScreen to save text screens before the
  269.     system is used in Graphics mode.
  270.  
  271.     Example:
  272.          CALL CopyScreen(frompage%, topage%, OOPS%)     Subroutine: HPage(page%)
  273.  
  274.          HPage masks the second 32k block of Hercules memory in or out of
  275.     the memory map.  If the second 32k is included in the memory map, QLIB's
  276.     video routines can use all Hercules screen pages.  The second 32k of
  277.     Hercules video memory conflicts with most color monitors' address space,
  278.     so HPage should be used to mask the second 32k out of the memory map for
  279.     two-monitor systems.  Page% = 0 masks the second 32k out of memory, any
  280.     other value of Page% allows the second block.
  281.  
  282.     Example:  CALL HPage(page%)
  283.  
  284.  
  285.  
  286.     Subroutine: PaintWindow(row0%, col0%, row1%, col1%, attr%)
  287.  
  288.          DVMT routine which changes the color attribute on a block of the 
  289.     active video page defined by row0%, col0%, row1%, col1%.  The entire block
  290.     is changed to attr%.  Changes color on video page set by SetQPage.
  291.  
  292.     Example:
  293.          row0% = 1
  294.          col0% = 1
  295.          row1% = 25
  296.          col1% = 80
  297.          CALL PaintWindow(row0%, col0%, row1%, col1%, attr%)
  298.          REM  we just changed the entire screen to color attr% without
  299.          REM  re-printing the text
  300.  
  301. THE QPRINT SERIES
  302.  
  303.     QuickPRINT DVMT routines print a string of text on the screen at very
  304.     high speed.  When used on CGA monitors, QPRINT routines slow down a bit
  305.     to avoid annoying "snow".  QPRINT routines include built-in LOCATE and
  306.     COLOR statements, and do not affect the cursor position.  ALL ASCII
  307.     characters may be used, but QPRINT routines work only in text mode. 
  308.     Color attributes may be calculated with CalcATTR.  Use SetQPage to set
  309.     QPRINT's active page.  All QPRINT subroutines require an 80-column screen.
  310.  
  311.  
  312.     Subroutine: Qprint(st$, row%, col%, attr%)
  313.     Subroutine: QprintU(st$, row%, col%, attr%)
  314.     Subroutine: QprintL(st$, row%, col%, attr%)
  315.     Subroutine: QprintCE(st$, row%, col%, attr%)
  316.  
  317.          Qprint, the fastest and most compact of the QPRINT series, will 
  318.     meet most needs.  QprintU will print a-z as upper case A-Z, and QprintL
  319.     will print A-Z as lower case a-z without changing st$.  QprintCE clears
  320.     the screen from the end of st$ to the edge of the screen.
  321.     
  322.     Example:
  323.          st$ = "This is a test of fast screen printing"
  324.          row% = 10: col% = 20
  325.          CALL Qprint(st$, row%, col%, attr%)
  326.  
  327.  
  328.  
  329.     Subroutine: QprintW(st$, row0%, col0%, row1%, col1%, attr%)
  330.  
  331.          QprintW adds word wrap to Qprint.  Text will be confined to a
  332.     window of the screen defined by ROW0%, COL0%, ROW1%, COL1%, and each line
  333.     of text will be broken between words unless the word is longer than
  334.     the width of the window, when the word will be broken at the edge of
  335.     the window. QprintW also clears the window before Qprinting the text.
  336.     If st$ = "", QprintW will clear the window and return to QuickBASIC.
  337.  
  338.     Example:
  339.          st$ = "This is a test of fast screen printing with word wrap"
  340.          row0% = 10: col0% = 20: row1% = 15: col1% = 50
  341.          CALL QprintW(st$, row0%, col0%, row1%, col1%, attr%)
  342.    Subroutine: Qread(st$, row%, col%)
  343.  
  344.          Uses DVMT to read a string of text from the active video page.
  345.     The initial length of st$ determines the length of the string returned
  346.     by Qread.  This is like Qprint in reverse.
  347.  
  348.     Example:
  349.          st$ = SPACE$(14)
  350.          row% = 12
  351.          col% = 5
  352.          CALL Qread(st$, row%, col%)
  353.          REM  st$ is now the first 14 characters on the active video page
  354.          REM  beginning at row 12, column 5
  355.  
  356.  
  357.  
  358.     Subroutine: Qscroll(row0%, col0%, row1%, col1%, attr%, lines%)
  359.  
  360.          A DVMT window scroll routine.  The area scrolled is limited by row0%,
  361.     col0%, row1%, col1%.  Positive values of lines% will scroll the screen up,
  362.     negative values scroll the screen down, and lines% = 0 will blank the
  363.     block of the screen.  Rows cleared by the scrolling action will be set to
  364.     color attribute attr%.
  365.  
  366.     Example:
  367.          row0% = 5
  368.          col0% = 10
  369.          row1% = 15
  370.          col1% = 75
  371.          lines% = 1
  372.          CALL Qscroll(row0%, col0%, row1%, col1%, attr%, lines%)
  373.          REM we just scrolled a block of the screen one row up
  374.    Subroutine: ReColorWindow(row0%, col0%, row1%, col1%, oldattr%, newattr%)
  375.  
  376.          Replaces oldattr% color with newattr% in the window defined by
  377.     row0%, col0%, row1%, col1%, without re-printing the contents of the
  378.     window.
  379.  
  380.     Example:
  381.          oldattr% = 7             ' gray on black to be replaced
  382.          newattr% = 14            ' with bright red on black
  383.          row0% = 10: col0% = 1    ' from row 10, column 1
  384.          row1% = 25: col1% = 80   ' to the end of the screen
  385.          CALL ReColorWindow(row0%, col0%, row1%, col1%, oldattr%, newattr%)
  386.  
  387.  
  388.  
  389.     Subroutine: SaveScreen(scrnSEG%, scrnOFF%, direction%)
  390.  
  391.          Uses DVMT to save/restore display screen video page set by SetQPage
  392.     in an array. Requires an array of 4000 bytes to save the screen (see
  393.     example).  Will check for retrace on CGA monitors to prevent "snow".
  394.     Text mode only.
  395.     
  396.     Example:
  397.          DIM scrn%(1999)                    ' 4000-byte array
  398.          REM direction% <> 0 to save screen
  399.          REM direction% = 0 to restore screen
  400.          scrnSEG% = VARSEG(scrn%(0))
  401.          scrnOFF% = VARPTR(scrn%(0))
  402.          CALL SaveScreen(scrnSEG%, scrnOFF%, direction%)
  403.  
  404.  
  405.  
  406.     Subroutine: SetQPage(page%)
  407.  
  408.          Sets active video page used by most DVMT video routines.
  409.  
  410.     Example:
  411.          page% = 2
  412.          CALL SetQPage(page%)
  413.          REM  Qread, SaveScreen, PaintWindow, ClrScreen,
  414.          REM  ClrBlock, Qscroll, ReColorWindow and the Qprint series
  415.          REM  will now use screen page 2.
  416. EQUIPMENT routines detect the presence or status of PC hardware.  Monitor
  417.     type, co-processor presence, CPU speed and keyboard toggles may be
  418.     determined, CPU speed toggle and keyboard toggles may be set.  CTRL,
  419.     ALT and SHIFT key status may also be monitored.
  420.  
  421.  
  422.  
  423.     Subroutine: ShiftKey(kbd%)
  424.  
  425.          Returns the status of the keyboard toggles and whether the CTRL, ALT
  426.     or SHIFT keys are pressed.  The code returned by ShiftKey is a copy of
  427.     the BIOS keyboard status byte, which must be ANDed to determine which key
  428.     toggles are set.  See explanation of keyboard status byte in Appendix B.
  429.  
  430.     Example:
  431.          rshift% = 1: lshift% = 2: shiftkey% = 3: ctrl% = 4: alt% = 8
  432.          scroll% = 16: numb% = 32: caps% = 64: insert% = 128
  433.          
  434.          CALL ShiftKey(kbd%)
  435.          IF (kbd% AND Rshift%) THEN PRINT "Right Shift pressed"
  436.          IF (kbd% AND Lshift%) THEN PRINT "Left Shift pressed"
  437.          IF (kbd% AND shiftkey%) THEN PRINT "Shift Key pressed"
  438.          IF (kbd% AND ctrl%) THEN PRINT "Ctrl Key pressed"
  439.          IF (kbd% AND alt%) THEN PRINT "Alt Key pressed"
  440.          IF (kbd% AND scroll%) THEN PRINT "ScrollLOCK ON"
  441.          IF (kbd% AND numb%) THEN PRINT "NumLOCK ON"
  442.          IF (kbd% AND caps%) THEN PRINT "CapsLOCK ON"
  443.          IF (kbd% AND insert%) THEN PRINT "INSERT ON"
  444.  
  445.  
  446.  
  447.     Subroutine: SetKeyToggle(kbd%)
  448.  
  449.          Sets the NumLOCK, CapsLOCK, ScrollLOCK and INSERT keyboard toggles.
  450.     See examples in Appendix B, "KEYBOARD STATUS BYTE".
  451.  
  452.     Example:
  453.          REM let's be sure the NumLOCK toggle is ON and CapsLOCK is off
  454.          scroll% = 16: numb% = 32: caps% = 64: insert% = 128
  455.          CALL GetKeyToggle(kbd%)       ' get present toggles
  456.          kbd% = (kbd% OR numb%)        ' this will set NumLOCK ON
  457.          kbd% = (kbd% AND (NOT caps%)) ' clears CapsLOCK bit
  458.          CALL SetKeyToggle(kbd%)
  459.  
  460.  
  461.  
  462.     Subroutine: Get8087(CHIPEXISTS%)
  463.  
  464.          Detects the presence of a math coprocessor in the system.
  465.     Value returned = -1 if 80x87 is present, 0 if not.
  466.  
  467.     Example:
  468.          CALL Get8087(CHIPEXISTS%)
  469.          IF chipexists% = -1 THEN PRINT "80x87 installed"     Subroutine: KbdType
  470.  
  471.          Detects enhanced (101-key) keyboards on IBM or clones.
  472.     Returns 1 if 101-key keyboard present, 0 if not.
  473.  
  474.     Example:
  475.          CALL KbdType(a%)
  476.          IF a% THEN PRINT "Enhanced keyboard attached to system"
  477.  
  478.  
  479.  
  480.     Subroutine: GetCRT(crt%)
  481.  
  482.           Tells  you what kind of display is being used.  The returned value
  483.      will be zero if it's MDA, &H80 if Hercules, -1 if CGA, +1 if EGA.
  484.  
  485.      Example:
  486.          CALL GetCRT(crt%)
  487.          SELECT CASE crt%
  488.               CASE -1
  489.                    PRINT "CGA Color"
  490.               CASE 0
  491.                    PRINT "Monochrome Display Adapter"
  492.               CASE 1
  493.                    PRINT "EGA Color"
  494.               CASE &H80                                    ' &H80 = 128
  495.                    PRINT "Hercules"
  496.          END SELECT
  497.  
  498.  
  499.  
  500.     Subroutine: GetSPEED(speed%)
  501.  
  502.          Determines whether the system is in "turbo" mode.  Returns 0 if
  503.     CPU is operating at normal speed, 1 if operating at faster CPU speed.
  504.     See also SetSPEED.
  505.  
  506.     Example:
  507.          CALL GetSpeed(speed%)
  508.  
  509.  
  510.  
  511.     Subroutine: SetSPEED(speed%)
  512.  
  513.          Sets speed toggle of most "turbo" clone computers.  SPEED% = 0 will
  514.     set normal CPU speed, any other value for SPEED% will set "turbo" speed.
  515.     Should not affect non-turbo computers (such as IBM PC, AT, etc.).  Good
  516.     style suggests that before using this function for the first time, you
  517.     should get the initial speed with GetSPEED and save it.  You should
  518.     then restore the CPU to that original state before exiting the program.
  519.  
  520.     Example:
  521.          CALL SetSpeed(speed%)
  522. INPUT routines replace INKEY$ commands
  523.  
  524.  
  525.     Subroutine: GetAKey(a%. extended%)
  526.  
  527.          Returns the ASCII character code of the first keypress waiting in the
  528.     keyboard buffer.  If extended% = -1, then the key pressed is an extended
  529.     keycode (such as the function keys F1 - F10) and a% is the ASCII code of
  530.     the second character of the keycode.  If the key pressed is not an
  531.     extended key, then extended% = 0.  If no keypresses are waiting in the
  532.     keyboard buffer, GetAKey waits until a key is pressed before it returns
  533.     to QuickBASIC.
  534.  
  535.     Example:
  536.          CALL GetAKey(a%, extended%)
  537.          PRINT chr$(a%);" was pressed"
  538.  
  539.  
  540.  
  541.     Subroutine: KeyWaiting(a%)
  542.  
  543.          Uses BIOS calls to determine whether a key is waiting in the keyboard
  544.     buffer, without reading the key.
  545.  
  546.     Example:
  547.          CALL KeyWaiting(a%)
  548.          IF a% = -1 THEN PRINT "A key has been pressed"
  549.  
  550.  
  551.  
  552.     Subroutine: YesNo(a%)
  553.  
  554.          Waits for either "Y" or "N" to be pressed, then returns the ASCII
  555.     character code of the key pressed.  The character code returned will be
  556.     the code for UPPER case "Y" or "N", regardless of whether the key pressed
  557.     was upper or lower case.
  558.  
  559.     Example:
  560.          PRINT "Are you sure? (Y/N)"
  561.          CALL YesNo(a%)
  562.          REM  ASC("Y") = 89, ASC("N") = 78
  563.          IF a% = 89 THEN
  564.                    .         ' instructions for Y response
  565.                    .
  566.                    .
  567.               ELSE
  568.                    .         ' instructions for N response
  569.                    .
  570.                    .
  571.          END IF
  572.     DATA routines manipulate numeric or string data.  Single data points
  573.     or portions of arrays may be shifted left or right (equivalent to
  574.     multiplying or dividing by powers of 2), integers may be added to selected
  575.     array elements, or arrays may be multiplied by real-number constants.
  576.     INSTR-like functions find the LAST match of a sub-string in a string, or
  577.     count the number of matches of a sub-string in a string.  QLIB Array
  578.     subroutines are MUCH faster and more compact than equivalent QuickBASIC
  579.     FOR ... NEXT loops.
  580.  
  581.  
  582.     Subroutine: AddINTArray(arSEG%, arOFF%, n%, value%, oops%)
  583.     Subroutine: AddLNGArray(arSEG%, arOFF%, n%, value%, oops%)
  584.  
  585.         Adds an integer to the first n% elements of an integer or long
  586.     integer array.  You can subtract by adding a negative number.  If the
  587.     results of the calculation ever go outside integer range (-32768 to
  588.     32767) or long integer range (-2147483648 to 2147483647), oops% is set
  589.     on return.  AddLNGArray does NOT work with QB2 or QB3.
  590.  
  591.     Example:
  592.          DIM Array1%(10000)
  593.           .
  594.           .
  595.          value% = -6: n% = 1000
  596.          arSEG% = VARSEG(Array1%(0))      ' arSEG = segment where array located
  597.          arOFF% = VARPTR(Array1%(0))      ' arOFF = offset of array in segment
  598.          CALL AddINTArray(arSEG%, arOFF%, n%, value%, oops%)
  599.          IF oops% THEN PRINT "Uh oh, overflowed somewhere..."
  600.          REM  we just subtracted six from the first 1000 elements of the array
  601.          REM  Array1().
  602.          REM  Use AddLNGArray when adding a value to a long integer array
  603.          REM  Array1&()
  604.  
  605.  
  606.  
  607.     Subroutine: CopyMem(fromSEG%, fromOFF%, toSEG%, toOFF%, bytes%, crt%)
  608.  
  609.          Copies data from one part of memory to another.  You supply
  610.     the source segment and offset, destination segment and offset, and 
  611.     number of bytes to move (0 - 32767).  This can be used to duplicate
  612.     numeric arrays, or to copy to or from the video buffer.  CopyMem will
  613.     wait for retrace periods before copying any data if crt% = -1 (to avoid
  614.     "snow" when copying to or from CGA video memory).
  615.      
  616.     Example:
  617.     DIM Array1%(1999)        ' 4000-byte array
  618.     CALL GetCRT(crt%)        ' crt% = -1 if monitor = CGA
  619.     fromSEG% = &HB800        ' CGA / EGA video memory segment
  620.     fromOFF% = 0             ' start of video memory buffer
  621.     toSEG% = VARSEG(Array1%(0))
  622.     toOFF% = VARPTR(Array1%(0))
  623.     bytes% = 4000            ' 25 rows x 160 bytes per row
  624.     CALL CopyMem(fromSEG%, fromOFF%, toSEG%, toOFF%, bytes%, crt%)
  625.     REM  we just stored the entire screen in array Array1%()    Subroutine: CountInString(search$, pattern$, count%)
  626.  
  627.          Counts the number of times pattern$ is found in search$.
  628.  
  629.     Example:
  630.          search$ = "This is a test string"
  631.          pattern$ = "is"
  632.          CALL CountInString(search$, pattern$, count%)
  633.          REM  count% = 2 in this example
  634.          PRINT "pattern found "; count%; " times"
  635.  
  636.  
  637.     Subroutine: InString(search$, pattern$, start%, position%)
  638.  
  639.              Similar to QuickBASIC's INSTR function, with additional
  640.     flexibility.  InString will find the first occurrence of pattern$ in
  641.     search$, and will return position% = position in search$ where pattern$
  642.     matches.  InString will optionally search for the LAST occurrence of
  643.     the pattern string in the search string, if start% is a negative number.
  644.     If start% = 0, InString will return the number of matches of pattern$ in
  645.     search$.  LEN(pattern$) must be less than the portion of search$ to be
  646.     searched.
  647.  
  648.     Example:
  649.          search$ = "This is a test string"
  650.          pattern$ = "is"
  651.          start% = 1               ' begin search at first char in Search$
  652.          CALL InString(search$, pattern$, start%, position%)
  653.                                   ' returns position% = 3
  654.  
  655.          start% = 4               ' begin search at fourth char in Search$
  656.          CALL InString(search$, pattern$, start%, position%)
  657.                                   ' returns position% = 6
  658.  
  659.          start% = -(len(search$)) ' search for LAST match
  660.          CALL InString(search$, pattern$, start%, position%)
  661.                                   ' returns position% = 6
  662.  
  663.          start% = -4              ' search for LAST complete match in first
  664.                                   ' 4 characters of search$
  665.          CALL InString(search$, pattern$, start%, position%)
  666.                                   ' returns position% = 3
  667.  
  668.          start% = 25              ' Starting position > LEN(search$)
  669.          CALL InString(search$, pattern$, start%, position%)
  670.                                   ' returns position% = 0
  671.  
  672.          start% = 0
  673.          CALL InString(search$, pattern$, start%, position%)
  674.                                   ' returns position% = 2
  675.  
  676.     Subroutine: MaxINTArray(aSEG%, aPTR%, n%, element%)
  677.     Subroutine: MinINTArray(aSEG%, aPTR%, n%, element%)
  678.  
  679.          Finds array element with maximum or minimum value between begin%
  680.     and begin% + n%.  The array must be an INTEGER array.
  681.  
  682.     Example:
  683.          DIM a%(99)      ' 100 element array
  684.          begin% = 0      ' start with the first array element
  685.          n% = 90        ' look at the first 90 array elements
  686.          aSEG% = VARSEG(a%(begin%))
  687.          aPTR% = VARPTR(a%(begin%))
  688.          CALL MaxINTArray(aSEG%, aPTR%, n%, element%)
  689.          PRINT "the maximum value is"; a%(element% + begin%)
  690.  
  691.  
  692.  
  693.     Subroutine: MaxLNGArray(aSEG%, aPTR%, n%, element%)
  694.     Subroutine: MinLNGArray(aSEG%, aPTR%, n%, element%)
  695.  
  696.          Finds array element with maximum or minimum value between begin%
  697.     and begin% + n%.  Works only with LONG INTEGER arrays.  Will not work
  698.     with QB2 or QB3.
  699.  
  700.     Example:
  701.          DIM a&(99)      ' 100 element LONG INTEGER array
  702.          begin% = 0      ' start with the first array element
  703.          n% = 90        ' look at the first 90 array elements
  704.          aSEG% = VARSEG(a&(begin%))
  705.          aPTR% = VARPTR(a&(begin%))
  706.          CALL MaxLNGArray(aSEG%, aPTR%, n%, element%)
  707.          PRINT "the maximum value is"; a&(element% + begin%)     Subroutine: MulINTArray(aSEG%, aPTR%, n%, number!)
  708.     Subroutine: MulLNGArray(aSEG%, aPTR%, n%, number!)
  709.     Subroutine: MulSNGArray(aSEG%, aPTR%, n%, number!)
  710.     Subroutine: MulDBLArray(aSEG%, aPTR%, n%, number#)
  711.  
  712.          MulArray subroutines multiply n% elements of an array
  713.     by a constant real number.  MulArray subroutines use the 8087 if
  714.     present, or uses QuickBASIC's floating point emulator if the 8087 is
  715.     not present.  MulArray subroutines will NOT work with QB2 or QB3, but
  716.     may work with QB87.
  717.  
  718.     MulINTArray is used if the array is a normal INTEGER array a%().
  719.     MulLNGArray is used if the array is a LONG INTEGER array a&().
  720.     MulSNGArray is used if the array is a real number array a!().
  721.     MulDBLArray is used if the array is a double-precision real number
  722.     array a#().  In this case the constant multiplied by the array is a
  723.     double-precision real number (number#).
  724.  
  725.     Note that aSEG% and aPTR% are integers, and for all MulArray routines
  726.     other than MulDBLArray, number! is a single-precision real number.
  727.  
  728.     Example:
  729.          DIM a#(99)     ' 100-element array, double precision
  730.               .
  731.               .
  732.               .
  733.          number# = 4.78
  734.          n% = 50        ' multiply a#(0) through a#(49) by number#
  735.          aSEG% = VARSEG(a#(0))  ' aSEG% = segment where a#(0) is stored
  736.          aPTR% = VARPTR(a#(0))  ' aPTR% = offset of a#(0) in aSEG%
  737.          CALL MulDBLArray(aSEG%, aPTR%, n%, number#)
  738.  
  739.  
  740.  
  741.     Subroutine: Today(month%, day%, year%, dayofweek%)
  742.  
  743.           Returns integer values for month (1 - 12), day of month (1 - 31),
  744.     year (1980 - 2099), and day of week (1 - 7, Sunday through Saturday)
  745.     from the system clock.
  746.  
  747.     Example:
  748.          CALL Today(month%, day%, year%, dayofweek%)      Subroutine: SetINTArray(ArSEG%, ArLOC%, SIZ%, SetVAL%, oops%)
  749.      Subroutine: SetLNGArray(ArSEG%, ArLOC%, SIZ%, SetVAL%, oops%)
  750.  
  751.           Set the first SIZ elements of an integer array or a long integer 
  752.      array to an integer value.  QB2 and QB3 do not support long integers.
  753.  
  754.      Example:
  755.           OPTION BASE 1: DIM ACK%(10000): SIZ%=10000
  756.            .
  757.            .
  758.           SetVAL%=-6
  759.           ArSEG% = VARSEG(ACK%(1))
  760.           ArLOC% = VARPTR(ACK%(1))
  761.           CALL SetINTArray(ArSEG%, ArLOC%, SIZ%, SetVAL%, oops%)
  762.           REM  we just set each element of the array ACK to -6
  763.  
  764.      Example:
  765.          OPTION BASE 1: DIM ACK&(10000): SIZ = 1000
  766.           .
  767.           .
  768.          SetVAL% = 14
  769.          ArSEG% = VARSEG(ACK&(1))
  770.          ArLOC% = VARPTR(ACK&(1))
  771.          CALL SetLNGArray(ArSEG%, ArLOC%, SIZ%, SetVAL%, oops%)
  772.          REM  we just set the first 1000 elements of the array ACK to 14
  773.  
  774.  
  775.  
  776.     Subroutine: Shift(value%, factor%)
  777.     Subroutine: ShiftLong(value&, factor%)
  778.  
  779.          Shifts all the bits in an integer factor% times, putting zeroes
  780.     in  the bit positions which have been vacated.  If factor% is positive,
  781.     the bits are shifted LEFT.  This effectively multiplies the value by a
  782.     power of two in most instances.  If factor% is negative, the bits are
  783.     shifted RIGHT ABS(factor%) times.  This is similar in effect to an integer
  784.     divide by a power of two.  SHIFT is used for 2-byte integers (VALUE%),
  785.     SHIFTLONG is used for 4-byte LONG integer values (VALUE&).  QB2 and QB3
  786.     do not support long integers. 
  787.     
  788.     Example:
  789.          VALUE% = 47: factor% = 3
  790.          CALL Shift(VALUE%, factor%)
  791.          REM  we just shifted VALUE% left three bits
  792.          REM  (in this case getting 47 * 2^3, or 376)
  793.     Example:
  794.          VALUE% = 47: factor% = -3
  795.          CALL Shift(VALUE%, factor%)
  796.          REM  we just shifted VALUE% right 3 bits
  797.          REM  (here getting 47 \ 2^3, or 5)
  798.     Subroutine: ShiftINTArray(aSEG%, aPTR%, n%, factor%, OOPS%)
  799.     Subroutine: ShiftLNGArray(aSEG%, aPTR%, n%, factor%, OOPS%)
  800.  
  801.     Description:
  802.          Shifts the bits of any n% elements of an integer array
  803.     ABS(factor%) times, putting zeros in the bit positions which have been
  804.     vacated.  Positive values of factor% shift array elements LEFT.  This
  805.     is equivalent to multiplying the element by a factor% power of 2 in most
  806.     instances.  Negative values of factor% cause an integer divide by a
  807.     ABS(factor%) power of 2.  ShiftLNGArray should be used if the array is
  808.     4-byte long integers.  OOPS% will be returned -1 if an overflow occurred.
  809.     QB2 and QB3 do not support long integers.
  810.  
  811.     Example:
  812.          DIM a%(100)
  813.          n% = 20
  814.          factor% = 1
  815.          aSEG% = VARSEG(a%(0))
  816.          aOFF% = VARPTR(a%(0))
  817.          CALL ShiftINTArray(aSEG%, aOFF%, n%, count%, OOPS%)
  818.          if OOPS% = -1 then PRINT "Oops, must have overflowed somewhere"
  819.          REM  we just shifted a%(0) through a%(19) one bit to the left
  820.  
  821.     DISK / FILE routines look for specified files on your disk, or report
  822.     disk status.
  823.  
  824.  
  825.      Subroutine: DriveSpace(drv$, total&, free&, oops%)
  826.  
  827.           Returns the amount of total and free space left on a given disk
  828.      drive.  The drive string may be any legal disk drive, or "@" (AT sign)
  829.      for the default drive, and must be at least one character long.  An
  830.      illegal drive or other error will cause oops% to be returned as -1.
  831.      Note that total& and free& are LONG integers.  Works with logical devices
  832.      up to 2,147 Megabytes.  DriveSpace will NOT work with QB2 or QB3.
  833.  
  834.      Example:
  835.           drv$="C:"
  836.            .
  837.            .
  838.           CALL DriveSpace(drv$, total&, free&, oops%)
  839.           IF oops% = -1 THEN
  840.                   PRINT "Invalid drive specification"
  841.                   ELSE
  842.                   PRINT "Free space on drive "; drv$; " is"; free&; "bytes."
  843.                   PRINT "Total space on drive "; drv$; " is"; total&; "bytes."
  844.           END IF
  845.  
  846.  
  847.  
  848.      Subroutine: EXIST
  849.  
  850.           Tells you if a given file already exists.  Returns an error code
  851.      if it doesn't, or -1 if it does.  Requires an ASCIZ filename without      
  852.      wildcards.
  853.  
  854.      Example:
  855.          FIL$="TEST.TXT" + CHR$(0)
  856.          CALL EXIST(FIL$,Errcode%)
  857.          IF Errcode% = -1 THEN PRINT "File already exists"
  858.          IF Errcode% = 0 THEN PRINT "Path exists"
  859.                                   ' FIL$ = "d:\path" + CHR$(0)
  860.          IF Errcode% = 2 THEN PRINT "Path found, file not found"
  861.          IF Errcode% = 3 THEN PRINT "Path or file not found"
  862.      Subroutine: GetSUB(d$, sub$, sublen%)
  863.  
  864.          Gets the current directory on disk d$.  The subdirectory string must
  865.     be 64 characters long.  Note that the returned string will NOT be started
  866.     by a backslash "\" character - you should add one if appropriate.  To get
  867.     the current directory on the default drive, set d$ = "@".  If d$ specifies
  868.     an invalid drive, sublen$ will be returned -1.  NOTE: d$ must be at least
  869.     one character long.
  870.  
  871.     Example:
  872.          sub$ = SPACE$(64)
  873.          d$ = "C"
  874.          CALL GetSUB(d$, sub$, sublen%)
  875.          IF sublen% = -1 THEN
  876.               PRINT d$ + " is not a valid drive"
  877.               ELSE
  878.               sub$ = "\" + LEFT$(sub$, sublen%)
  879.          END IF
  880.  
  881.  
  882.  
  883.     Subroutine: GetDRIVE(drv%)
  884.  
  885.          Returns the ASCII character code of the default drive.
  886.  
  887.     Example:
  888.          CALL GetDRIVE(drv%)
  889.          drive$ = CHR$(drv%)+":"
  890.          PRINT "The default drive is "; drive$
  891.  
  892.  
  893.  
  894.     Subroutine: SetDRIVE(d$)
  895.  
  896.          Sets d$ as the default drive.  D$ may be any valid disk drive or 
  897.     other logical device (such as a RAMdisk).
  898.  
  899.     Example:
  900.          d$ = "a:"           ' the drive specifier d$ may be upper or lower
  901.                              ' case and need not include the colon.
  902.          CALL SetDRIVE(d$)   ' drive A: is now the default drive
  903. APPENDIX A - Color attributes for video displays
  904.  
  905.     Colors values for IBM (and compatible) color displays are as follows:
  906.  
  907.          Color          Value          notes
  908.  
  909.          black            0       high-intensity black = gray
  910.          blue             1
  911.          green            2
  912.          cyan             3
  913.          red              4
  914.          magenta          5
  915.          brown            6       high-intensity brown = yellow
  916.          "white"          7       normal-intensity "white" looks muddy
  917.  
  918.  
  919.     For IBM Monochrome, Hercules and compatible displays:
  920.  
  921.          foreground value     appearance
  922.  
  923.                 0                 black if background% = 0 or 7
  924.                                   if background% between 1 and 6,
  925.                                   normal if bright% = 0
  926.                                   bright if bright% = 1
  927.                                             
  928.                 1              underlined        bright + underline
  929.                                                  if bright% = 1
  930.  
  931.               2 - 7               normal         bright if bright% = 1
  932.  
  933.          background value     appearance
  934.  
  935.               0 - 6                black
  936.                 7                  normal color if foreground% = 0
  937.  
  938.                                    bright if blink% = 1, SetBLINK(0)
  939.                                    called, and foreground% = 0
  940.  
  941.                                    black if foreground% <> 0
  942. APPENDIX B - KEYBOARD STATUS BYTE
  943. Subroutines ShiftKey and SetKeyToggle
  944.  
  945.          The keyboard status byte consists of 8 bits, 4 of which are used
  946.     to indicate the status of the INSERT, CapsLOCK, NumLOCK and ScrollLOCK
  947.     keys.  For each of these keys, one bit is set ( =1 ) if the key is
  948.     toggled ON.  The bit is zeroed if the key is OFF.
  949.  
  950.     The keyboard status byte:
  951.                         <--- bit positions -->
  952.                         7  6  5  4  3  2  1  0
  953.                         │  │  │  │  │  │  │  └ 1 = Right shift pressed
  954.                         │  │  │  │  │  │  └─── 1 = Left shift pressed
  955.                         │  │  │  │  │  └────── 1 = either Control pressed
  956.                         │  │  │  │  └──────────1 = either Alt pressed
  957.                         │  │  │  └─────────────1 = ScrollLOCK active
  958.                         │  │  └────────────────1 = NumLOCK active
  959.                         │  └───────────────────1 = CapsLOCK active
  960.                         └──────────────────────1 = INSERT active
  961.  
  962.     BASIC does not understand individual bits, but armed with a little 
  963.     knowledge, you can out-think BASIC.  BASIC interprets each bit as a
  964.     power of 2, so that 
  965.          bit 0 if on =   1
  966.          bit 1 if on =   2
  967.          bit 2 if on =   4
  968.          bit 3 if on =   8
  969.          bit 4 if on =  16
  970.          bit 5 if on =  32
  971.          bit 6 if on =  64
  972.          bit 7 if on = 128
  973.  
  974.     Thus, if NumLOCK and CapsLOCK are active, but ScrollLOCK and INSERT are
  975.     off, BASIC will tell you that the keyboard status byte = 32 + 64 = 96
  976.     (this is bit 5 and bit 6 ON, all other bits off).  After calling
  977.     ShiftKey, you may determine which key or keys are ON by ANDing the
  978.     status byte with the value associated with that key's bit.
  979.  
  980.     Example:  Let's assume that NumLOCK and ScrollLOCK are ON, INSERT and
  981.     CapsLOCK are off.
  982.  
  983.          CALL ShiftKey(kbd%)
  984.          PRINT kbd%          ' prints 48 (results from 16+32)
  985.          IF (kbd% AND 16) THEN PRINT "ScrollLOCK ON"
  986.          IF (kbd% AND 32) THEN PRINT "NumLOCK ON"
  987.          IF (kbd% AND 64) THEN PRINT "CapsLOCK ON"  ' will not be printed
  988.                                                       in this example
  989.          IF (kbd% AND 128) THEN PRINT "INSERT ON"   ' will not be printed
  990.                                                       in this example
  991.  
  992.     The keyboard toggles may be stored as a single integer (kbd%) in 
  993.     order to restore the original status at a later time.
  994.  
  995.     Setting the keyboard toggles involves setting the individual bits
  996.     in the status byte.  The AND, OR and NOT operators come in handy
  997.     here.
  998.  
  999.     OR compares the bits in both operands and sets all bits in the resulting
  1000.     byte corresponding to the bits in the operands.
  1001.  
  1002.     Example: set a keyboard toggle
  1003.  
  1004.               bits in operand a   0 0 1 0 0 0 0 0    (bit 5 set, = 32)
  1005.                       operand b   1 0 0 1 0 0 0 0    (bits 4 and 7 set)
  1006.                                   ───────────────
  1007.                          a OR b   1 0 1 1 0 0 0 0    ( bits 4, 5, and 7 set)
  1008.  
  1009.     In this way, an individual toggle may be added to kbd% and set via
  1010.     SetKeyToggle.  If bit 5 had already been set in operand b, the result
  1011.     would be the same.
  1012.  
  1013.     Example: turn a keyboard toggle off
  1014.  
  1015.               bits in operand a   0 0 1 0 0 0 0 0    (bit 5 set, = 32)
  1016.                           NOT a   1 1 0 1 1 1 1 1    (NOT reverses all bits)
  1017.                            kbd%   1 0 1 1 0 0 0 0    ( a OR b, above)
  1018.                                   ─────────────── 
  1019.                (NOT a) AND kbd%   1 0 0 1 0 0 0 0
  1020.  
  1021.     As you can see, AND sets bits in the result only if the corresponding
  1022.     bits are set in BOTH operands.  In this example, the bit in kbd% for
  1023.     NumLOCK is turned off.  If SetKeyToggle is called with this new kbd%,
  1024.     NumLOCK will be turned off.
  1025.  
  1026. APPENDIX C - QLIB and QB3
  1027.  
  1028.     This appendix applies to use of QLIB with QuickBASIC 2, QuickBASIC 3
  1029.     and QB3's QB87.  QLIB was developed originally for QuickBASIC 4, but
  1030.     many of its subroutines may be used equally well with earlier versions
  1031.     of QuickBASIC.  Any subroutines which I have found to be incompatible
  1032.     with earlier QuickBASICs are clearly marked in the description of each
  1033.     routine.  As my time permits, I will modify those offending subroutines
  1034.     to enhance compatability of QLIB with all QuickBASIC versions.  In most
  1035.     cases, this appendix applies equally to QB2 and QB3.  I have not begun
  1036.     testing QLIB with QB3's QB87.  I expect that the MulArray subroutines
  1037.     will work properly.
  1038.  
  1039. Array Pointers
  1040.  
  1041.     Pointers to numeric arrays are passed to QLIB subroutines using
  1042.     those arrays.  Both SEGMENT and OFFSET pointers must be passed, because
  1043.     many types of arrays are located outside QuickBASIC's default data 
  1044.     segment.
  1045.  
  1046.     QuickBASIC 4 users have the VARSEG and VARPTR commands, which return an
  1047.     array's segment and offset, respectively, to QuickBASIC.  Earlier versions
  1048.     of QuickBASIC lack the VARSEG command, but QLIB has two comparable
  1049.     routines which may be used with either QB3 or QB4.
  1050.  
  1051.     Subroutine: DataSEG(ds%)
  1052.  
  1053.          DataSEG returns QuickBASIC's default data segment, where static
  1054.     arrays are stored.  ds% may be used along with QuickBASIC's VARPTR
  1055.     to address static arrays for QLIB array routines.
  1056.  
  1057.     Example:
  1058.          DIM a%(1999)        ' 2000-byte static array
  1059.               .
  1060.               .
  1061.               .
  1062.          call DataSEG(ds%)
  1063.          aPTR% = VARPTR(a%(0))
  1064.          CALL ScreenSave(ds%, aPTR%, 1)
  1065.          REM  this example saved the screen in array a% to recall later
  1066.  
  1067.  
  1068.  
  1069.     Subroutine: SegPTR(a(0), aSEG%, aPTR%)
  1070.  
  1071.          SegPTR returns both the segment and the offset pointers to a(0).
  1072.     a() may be any numeric array.  aSEG% and aPTR% may be usd to address
  1073.     either static or dynamic arrays for QLIB array routines.  Note that 
  1074.     SegPTR is called using CALLS instead of CALL.
  1075.  
  1076.          Example:
  1077.          DIM a%(1999)        ' 2000-byte array
  1078.               .
  1079.               .
  1080.               .
  1081.          CALLS SegPTR(a%(0), aSEG%, aPTR%)
  1082.          CALL ScreenSave(aSEG%, aPTR%, 1)
  1083.          REM  this example saved the screen in array a% to recall later
  1084.  
  1085.  
  1086.     QB3 has a serious bug which creates a flawed object code when working
  1087.     within the QuickBASIC editor to create stand-alone .EXE files.  To use
  1088.     QLIB to make stand-alone .EXE files, compile and link your programs from
  1089.     the DOS command line:
  1090.  
  1091.          to compile:
  1092.          QB yourprog /O;
  1093.  
  1094.          to link:
  1095.          LINK yourprog,,NUL,QLIB.LIB;
  1096.  
  1097.     QLIB will work fine when creating or debugging code within the QuickBASIC
  1098.     editor, but you must work from the DOS command line to make your stand-
  1099.     alone .EXE files.
  1100.